home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d3
/
smooth.arc
/
SMOOTH.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-01-10
|
41KB
|
828 lines
;--------------------------------------------------------------------------
; SMOOTH * PC Magazine * Feb 14, 1989
; Provides forward, backward and variable speed smooth scrolling
; of a file to the display. Requires Ega or Vga.
; Syntax: SMOOTH filespec
;--------------------------------------------------------------------------
_TEXT SEGMENT PUBLIC 'CODE'
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
ORG 100H
START: JMP MAIN
; DATA AREA
; ---------
DB CR,SPACE,SPACE,SPACE
COPYRIGHT DB CR,LF,"SMOOTH 1.0 (C) 1989 Ziff Communications Co."
PROGRAMMER DB CR,LF,"PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
DB "Syntax: SMOOTH filespec [/W][/Snn][Cmmm]",CR,LF
DB "/W = Wordstar; /S = nn Speed; /C = mmm Color",CR,LF,LF
DB "Use: ",24,25,", PgUp, PgDn, Home, End; Esc to Exit",CR,LF
DB "+ = faster; - = slower; Space bar = pause; (0-9) = speed"
COPY_LENGTH EQU $ - COPYRIGHT
DB CR,LF,LF,"$",CTRL_Z
NOT_ENOUGH DB "Not enough memory$"
NOT_EGA_VGA DB "Requires Ega/Vga$"
NOT_FOUND DB "File not found$"
CR EQU 13
LF EQU 10
TAB EQU 9
CTRL_Z EQU 26
SPACE EQU 32
BOX EQU 254
STATUS_REG DW 3BAH
VIDEO_SEGMENT DW 0B000H
INDEX_SEGMENT DW ?
CRT_COLS DW ?
CRT_LINE DW ?
CRT_LEN DW ?
CRT_START DW 0
CRT_END DW ?
LAST_LINE DW ?
STRIP_MASK DB 0FFH
ATTRIBUTE DB 07H
DISPLAY_ROWS DW ?
SCAN_LINESx2 DW ?
UP EQU 0
DOWN EQU 1
DIRECTION DB UP
CURRENT_SCANx2 DW 0
SCAN_SPEED DW 3
THIRTY_K EQU 30 * 1024
FILE_HANDLE DW ?
FILE_END DW ?
STORE_FLAG DB 1
DISPATCH_KEY DB 1, 48H, 50H, 49H, 51H, 47H, 4FH, 39H, 0DH, 0CH, 4EH, 4AH
DISPATCH_CNT EQU $ - DISPATCH_KEY
DISPATCH_TABLE DW EXIT, UP_ARROW, DOWN_ARROW, PGUP, PGDN, HOME
DW END_KEY, SPACE_BAR, PLUS, MINUS, PLUS, MINUS
DISPATCH_END EQU $ - 2
; CODE AREA
; ---------
MAIN PROC NEAR
CLD ;All string operations forward.
MOV BX,2000H ;Allocate 128K of memory.
MOV AH,4AH
INT 21H
MOV DX,OFFSET NOT_ENOUGH ;Exit with message if not enough.
JC ERROR_MSG
MOV SP,0FFFEH ;Stack to top of code segment.
MOV AX,CS
ADD AX,1000H ;Use 2nd 64K for line indices.
MOV INDEX_SEGMENT,AX
MOV AX,40H ;Point to BIOS data area.
MOV ES,AX
MOV AX,500H ;Make sure zero video page.
INT 10H
MOV AX,1A00H ;Get display info.
INT 10H
CMP AL,1AH ;Function supported?
JNZ CK_EGA ;If no, not VGA; check EGA.
CMP BL,7 ;Else, monochrome VGA?
JZ GET_CRT_MODE ;If yes, OK.
CMP BL,8 ;Else, color VGA?
JZ GET_CRT_MODE ;If yes, OK.
CK_EGA: MOV AH,12H
MOV BL,10H ;Get EGA information.
INT 10H
MOV DX,OFFSET NOT_EGA_VGA
CMP BL,10H ;Is there an EGA?
JZ ERROR_MSG ;If no, exit with message.
TEST ES:BYTE PTR [87H],8 ;Is EGA active?
JZ GET_CRT_MODE ;If yes, continue.
ERROR_MSG: PUSH DX ;Else, exit with message.
MOV DX,OFFSET COPYRIGHT ;Display copyright and syntax.
CALL PRINT_STRING
POP DX
CALL PRINT_STRING
MOV AL,1 ;ERRORLEVEL = 1
JMP TERMINATE ;Exit.
GET_CRT_MODE: MOV BL,ES:[49H] ;Retrieve CRT_MODE.
CMP BL,7 ;Is it mono?
JZ GET_COLS ;If yes, use defaults.
MOV STATUS_REG,3DAH ;Else, mono status register.
MOV VIDEO_SEGMENT,0B800H ;And mono video segment.
CMP BL,2 ;Is mode BW80?
JZ GET_COLS ;If yes, defaults.
OR BL,BL ;Is mode BW40?
JZ GET_COLS ;If yes, continue.
MOV ATTRIBUTE,17H ;Else, use color attribute.
CMP BL,3 ;Are we in CO80 or CO40?
JBE GET_COLS ;If yes, done here.
MOV AX,3 ;Else, change to CO80.
INT 10H
GET_COLS: MOV AX,ES:[4AH] ;Retrieve CRT_COLS
MOV CRT_COLS,AX ; and save.
SHL AX,1 ;Double for attribute
MOV CRT_LINE,AX ; and save.
PUSH AX ;Save line length.
MOV BH,2 ;Get font information.
MOV AX,1130H
INT 10H
SHL CX,1 ;Double scan lines/character.
MOV SCAN_LINESx2,CX ; and save.
INC DL ;Adjust character rows.
XOR DH,DH
MOV DISPLAY_ROWS,DX ;Store rows on screen.
POP AX ;Retrieve screen width.
MUL DL ; Times rows
MOV CRT_LEN,AX ; equals CRT length.
;-------------------------------------------------------;
; Check for /W WordStar, /S speed or /C color switches. ;
;-------------------------------------------------------;
MOV SI,81H ;Point to command line.
NEXT_SWITCH: LODSB ;Get a byte.
CMP AL,CR ;Is it carriage return?
JZ PARSE ;If yes, done here.
CMP AL,"/" ;Is it switch delimiter?
JNZ NEXT_SWITCH ;If no, next byte.
MOV BYTE PTR [SI-1],0 ;Else, ASCIIZ it out.
LODSB ;Get the switch character.
CMP AL,CR ;Make sure it's not CR
JZ PARSE ; so we don't go past end.
AND AL,5FH ;Capitalize.
CMP AL,"W" ;Is it "W"?
JNZ CK_S ;If not, check "S".
MOV STRIP_MASK,7FH ;Else, we will strip high bit.
CK_S: CMP AL,"S" ;Is it "S"?
JNZ CK_C ;If no, check "C".
CALL DECIMAL_INPUT ;Else, get speed request.
XOR BH,BH
MOV AX,SCAN_LINESx2
CMP BX,AX ;If greater than maximum,
JBE SAVE_SPEED
MOV BX,AX ; use maximum, else use request.
SAVE_SPEED: MOV SCAN_SPEED,BX
JMP SHORT NEXT_SWITCH ;Get next switch.
CK_C: CMP AL,"C" ;Is it "C"?
JNZ NEXT_SWITCH ;If no, next switch.
CALL DECIMAL_INPUT ;Else, get color request.
OR BL,BL ;If black on black, skip.
JZ NEXT_SWITCH
MOV ATTRIBUTE,BL ;Else, save color request.
JMP NEXT_SWITCH ;Next switch.
;---------------------------------------;
; Parse the command line for filespec. ;
;---------------------------------------;
PARSE: MOV SI,81H ;Point to command line again.
NEXT_PARSE: LODSB ;Get a byte.
CMP AL,SPACE ;Parse off leading delimiters.
JA LEADING_END
OR AL,AL ;If ASCIIZ reached, done.
JNZ NEXT_PARSE
LEADING_END: MOV DX,SI
DEC DX ;Adjust pointer.
FIND_END: LODSB ;Find end of filespec.
CMP AL,SPACE ;If none white space, continue.
JAE FIND_END
MOV BYTE PTR [SI-1],0 ;ASCIIZ filespec.
MOV AX,3D00H ;Open file for reading.
INT 21H
MOV DX,OFFSET NOT_FOUND ;If fail, exit with message.
JNC SAVE_HANDLE
JMP ERROR_MSG
SAVE_HANDLE: MOV FILE_HANDLE,AX ;Else, save handle.
CALL FIRST_READ ;Read 30K.
MOV ES,VIDEO_SEGMENT ;Clear the screen by writing
MOV CX,CRT_LEN ; the CRT length / 2 words
SHR CX,1
XOR DI,DI
MOV AH,ATTRIBUTE ; with spaces of attribute.
MOV AL,SPACE
REP STOSW
MOV BL,ATTRIBUTE ;Add border with same attribute.
CALL SET_BORDER
MOV DX,DISPLAY_ROWS ;Place cursor in middle of row
XCHG DH,DL ; of display.
SHR DH,1
CALL SET_CURSOR
PUSH SI ;Save file pointer.
MOV SI,OFFSET COPYRIGHT ;Display copyright and syntax
MOV CX,COPY_LENGTH ; with attribute.
NEXT_COPY: LODSB
MOV AH,0EH
INT 10H
LOOP NEXT_COPY
POP SI ;Retrieve file pointer.
XOR BP,BP ;Use BP as line file pointer.
CALL ADVANCE ;Write first line.
MOV CRT_END,DI ;Save CRT end.
;*************** MAIN LOOP *****************;
; Poll the keyboard then scroll the screen. ;
;*******************************************;
INPUT: MOV AH,1 ;Is there a keystroke ready?
INT 16H
JZ SCROLL_PAGE ;If no, scroll the page.
GET_KEY: XOR AH,AH ;Else, get the keystroke.
INT 16H
SUB AL,"0" ;If not number, check functions.
JC FUNCTION
CMP AL,9
JA FUNCTION
XOR AH,AH ;Else, change speed to number.
CALL DO_SPEED
JMP SHORT SCROLL_PAGE
FUNCTION: PUSH DI ;Save some registers.
PUSH ES
PUSH CS
POP ES
MOV AL,AH ;Scan code in AL.
MOV DI,OFFSET DISPATCH_KEY ;Check dispatch table.
MOV CX,DISPATCH_CNT
REPNZ SCASB
POP ES ;Restore registers.
POP DI
JNZ INPUT ;Skip keystroke if no match.
SHL CX,1 ;Else, look up subroutine
MOV BX,OFFSET DISPATCH_END
SUB BX,CX
CALL [BX] ; and process command.
SCROLL_PAGE: CALL SCROLL ;Scroll the page.
JMP SHORT INPUT ;Next input.
;---------------------------------------------------;
EXIT: MOV BX,FILE_HANDLE ;Retrieve file handle
MOV AH,3EH ; and close the file.
INT 21H
MOV BX,CRT_LINE
MOV SI,CRT_START ;Point to current visible page.
MOV AX,SCAN_LINESx2 ;If current scan line is more
SHR AX,1 ; than half of character scan
CMP CURRENT_SCANx2,AX ; lines, move to next line.
JB MOVE_PAGE
ADD SI,BX
MOVE_PAGE: XOR DI,DI
MOV CX,CRT_LEN
SUB CX,BX
SHR CX,1
MOV AH,ATTRIBUTE ;Value to be used on last line.
XOR AL,AL
PUSH DS
MOV DS,VIDEO_SEGMENT
REP MOVSW ;Move the active page to page 0.
MOV CX,BX
SHR CX,1
REP STOSW ;Clear the last line.
POP DS
XOR BX,BX ;Return to a normal scan line of
XOR CX,CX ; zero and an offset of zero.
CALL SET_CRT
XOR BL,BL ;Border back to black.
CALL SET_BORDER
MOV DX,DISPLAY_ROWS ;Put cursor on bottom of screen.
XCHG DH,DL
DEC DH ;Up a line so screen won't scroll
DEC DH ; with new DOS prompt.
CALL SET_CURSOR
XOR AL,AL ;ERRORLEVEL zero.
TERMINATE: MOV AH,4CH ;Return to DOS.
INT 21H
MAIN ENDP
; ***************
; * SUBROUTINES *
; ***************
;-----------------------------------------;
; What follows is the keyboard functions. ;
;-----------------------------------------;
UP_ARROW: CMP DIRECTION,DOWN ;Are we already scrolling down?
JZ CK_SPEED ;If yes, skip and go check speed.
CALL CK_PAGE ;Else, is a full page displayed?
JBE ARROW_END ;If no, ignore.
INC BX ;Else, move file pointer up
CALL PAGE_UP ; display rows plus one.
MOV DIRECTION,DOWN ;Change scroll direction to down.
JMP SHORT CK_SPEED ;Check if speed is zero.
ARROW_END: RET
DOWN_ARROW: CMP DIRECTION,UP ;Are we already scrolling up?
JZ CK_SPEED ;If yes, skip and go check speed.
CALL MOVE_DOWN ;Else, move file pointer to
MOV DIRECTION,UP ; bottom of page; direction down.
CK_SPEED: CMP SCAN_SPEED,0 ;If scroll speed non-zero,
JNZ ARROW_END ; done, else increase by one.
PLUS: MOV AX,SCAN_SPEED ;Increase scan speed by one
INC AX ; scan line unless already
DO_SPEED: CMP AX,SCAN_LINESx2 ; maximum speed.
JBE STORE_SPEED
RET
MINUS: MOV AX,SCAN_SPEED ;Decrease scan speed by one
DEC AX ; scan line unless already
JS MINUS_END ; speed of zero (stationary).
STORE_SPEED: MOV SCAN_SPEED,AX
MINUS_END: RET
PGUP: CMP DIRECTION,DOWN ;Are we scrolling opposite of
JZ REVERSE_UP ; page request? If yes, reverse.
CALL CK_PAGE ;Else, is a full page displayed?
JBE PGUP_END ;If no, ignore.
INC BX ;Else, move file pointer to top
CALL PAGE_UP ; of page.
CALL CK_PAGE ;Retrieve page length.
JA DO_PAGE_UP ;Can we page up a full page?
CALL PARTIAL_PAGE ;If no, partial page.
JZ DO_WRITE ;If already home, skip.
DO_PAGE_UP: CALL PAGE_UP ;Else, move to top of prev. page.
DO_WRITE: CALL WRITE_DOWN ;Write the page. File pointer
JMP SHORT PGUP_END ; ends up back at bottom so done.
REVERSE_UP: CALL CK_PAGE ;If full page continue,
JAE DO_REVERSE ; else use partial page.
CALL PARTIAL_PAGE
JZ PGUP_END ;If already home, ignore.
DO_REVERSE: MOV SI,LAST_LINE ;Else, retrieve last line.
CALL PAGE_UP ;Move up a page.
CALL WRITE_DOWN ;Write that page.
CALL MOVE_UP ;Move file pointer back to top.
PGUP_END: RET
PGDN: CMP DIRECTION,DOWN ;Are we scrolling opposite of
JZ REVERSE_DN ; page request? If yes, reverse.
CALL NEW_PAGE ;Else, move to next page.
RET
REVERSE_DN: CALL MOVE_DOWN ;Else, move to bottom of page.
CALL NEW_PAGE ;Display next page.
CALL MOVE_UP ;Move file pointer back to top.
PGDN_END: RET
HOME: MOV CURRENT_SCANx2,0 ;Move to scan line zero.
CMP DIRECTION,DOWN ;Are we scrolling opposite of
JZ REVERSE_HOME ; page request? If yes, reverse.
CALL CK_PAGE ;Is a full page displayed?
JA GO_HOME ;If yes, continue, else ignore.
RET
REVERSE_HOME: OR BP,BP ;Are we already home?
JZ HOME_END ;If yes, ignore.
MOV SI,LAST_LINE ;Else, retrieve last line.
GO_HOME: MOV BX,BP ;Move up the number of lines
SHR BX,1 ; currently displayed.
CALL PAGE_UP
CALL WRITE_DOWN ;Write the first page.
CK_REVERSE: CMP DIRECTION,DOWN ;Scrolling down?
JNZ HOME_END ;If no, done.
CALL MOVE_UP ;Else, move file pointer to top.
HOME_END: RET
END_KEY: MOV BX,0FFFFH ;Move down until bottom reached.
CMP DIRECTION,DOWN ;Are we scrolling opposite of
JNZ DO_END ; page request? If yes, reverse.
MOV SI,LAST_LINE ;Retrieve last line.
DO_END: CALL NO_WRITE ;Top of last page and write.
JMP SHORT CK_REVERSE ;Check if file pointer correction
SPACE_BAR: MOV AH,1 ;Wait until keystroke ready
INT 16H
JZ SPACE_BAR
CMP AL,SPACE ;If space bar, eat keystroke.
JNZ SPACE_END ;Else, return to process.
XOR AH,AH
INT 16H
SPACE_END: RET
;-----------------------------;
; Function support routines. ;
;-----------------------------;
PARTIAL_PAGE: MOV CURRENT_SCANx2,0 ;Move to scan line zero.
MOV BX,BP ;Return with number of lines
SHR BX,1 ; displayed.
OR BX,BX ;Zero flag if already home.
RET
WRITE_DOWN: CALL CK_PAGE ;Write a full page plus one
INC BX ; line to display.
MOV STORE_FLAG,1
CALL WRITE_PAGE
RET
MOVE_UP: CALL CK_PAGE ;Move up a full page plus one.
INC BX
CALL PAGE_UP
MOV LAST_LINE,SI
RET
MOVE_DOWN: CALL CK_PAGE ;Move down a full page.
INC BX
MOV SI,LAST_LINE
MOV STORE_FLAG,0
CALL WRITE_PAGE
RET
NEW_PAGE: CALL CK_PAGE ;Get page size.
NO_WRITE: PUSH BX ;Save.
MOV STORE_FLAG,0 ;Move down the page request.
CALL WRITE_PAGE
MOV CX,BX ;Save lines moved.
CALL CK_PAGE ;Get page size.
POP AX ;Retrieve page request.
JBE SHORT_PAGE ;If short page, special.
INC BX ;Else, move up page plus one.
CALL PAGE_UP
CALL WRITE_DOWN ;And write the page.
CALL CK_FILE_END
JNC NEW_PAGE_END
MOV AX,SCAN_LINESx2 ;Change scan line to last line.
DEC AX
MOV CURRENT_SCANx2,AX
RET
SHORT_PAGE: MOV BX,AX ;For short files, move back
SUB BX,CX ; up the number of lines
JZ NEW_PAGE_END ; moved down. Zero net result
CALL PAGE_UP ; same as ignore.
NEW_PAGE_END: RET
;------------------------------------------------------------;
; OUTPUT: BX = Display rows + 1; JBE set if not a full page ;
;------------------------------------------------------------;
CK_PAGE: MOV BX,DISPLAY_ROWS ;Retrieve rows on screen.
SHL BX,1 ;Double for word index.
CMP BP,BX ;Is there a full page?
PUSHF ;Preserve results.
SHR BX,1 ;Return BX = rows.
POPF ;Restore flags.
RET
;------------------------------------------------;
; INPUT: BX = number of lines to move backward. ;
;------------------------------------------------;
PAGE_UP: DEC BP ;Index back one line.
DEC BP ;It's a word index.
CALL CK_BACKWARD ;Move back one line.
DEC BX ;Continue until requested lines.
JNZ PAGE_UP
RET
;----------------------------------------;
; INPUT: BX = Number of lines to write. ;
;----------------------------------------;
WRITE_PAGE: MOV DI,CRT_START ;Point to CRT start.
NEXT_WRITE: CALL CK_FILE_END ;End of file?
JC WRITE_END ;If yes, done.
CALL ADVANCE ;Else, write a line.
DEC BX ;Continue until requested lines.
JNZ NEXT_WRITE
WRITE_END: RET
;******************************************;
SCROLL: MOV AX,SCAN_LINESx2 ;Retrieve scan lines times two.
MOV BX,CURRENT_SCANx2 ;Retrieve current scan line X 2.
CMP DIRECTION,DOWN ;Are we scrolling down?
JZ SCROLL_DOWN ;If yes scroll down.
ADD BX,SCAN_SPEED ;Else, scroll up; add speed.
CMP BX,AX ;Is it a wrap?
JB SCROLL_IT ;If no, display new scan line.
CALL CK_FILE_END ;Are we at end of file?
JNC CK_CRT_UP ;If no, continue
MOV BX,AX ;Else, move to last scan line.
DEC BX
JMP SHORT SCROLL_IT
CK_CRT_UP: SUB BX,AX ;Subtract scan lines.
MOV AX,CRT_LINE ;Retrieve CRT line length.
ADD CRT_START,AX ;Move CRT start to next line.
CALL CK_CRT_END ;Check if end of video memory.
MOV STORE_FLAG,1 ;Write a new line.
CALL ADVANCE
MOV CRT_END,DI ;Save new CRT end.
SCROLL_IT: MOV CURRENT_SCANx2,BX ;Store new scan line.
MOV CX,CRT_START ;Program registers to
CALL SET_CRT ; new CRT start and scan line.
SCROLL_END: RET
SCROLL_DOWN: SUB BX,SCAN_SPEED ;Scroll down; subtract speed.
JNC SCROLL_IT ;If not wrap, display new scan.
ADD BX,AX ;Else, add scan lines.
OR BP,BP ;Are we at home position?
JNZ CK_CRT_DN ;If no, continue.
XOR BX,BX ;Else, set scan line to zero.
JMP SHORT SCROLL_IT
CK_CRT_DN: CALL CK_CRT_START ;Check if start of video memory.
MOV SI,LAST_LINE ;Retrieve last line.
DEC BP ;Decrement file pointer
DEC BP ; line start index.
CALL CK_BACKWARD ;Move file pointer up one line.
MOV DI,CRT_START ;Point to start of CRT.
MOV STORE_FLAG,1 ;Write the line at top.
CALL LINES
JMP SHORT SCROLL_IT ;Set new scan line.
;------------------------------;
; Scroll support subroutines. ;
;------------------------------;
CK_CRT_START: MOV AX,CRT_LINE ;Retrieve bytes in CRT line.
MOV DI,CRT_START ;Retrieve current CRT start.
OR DI,DI ;Is it offset of zero?
JNZ MOVE_CRT ;If no, move down one line.
PUSH SI ;Else, save file pointer.
PUSH DS ;Preserve data segment.
XOR SI,SI ;Move page zero to top
MOV DI,THIRTY_K ; of video memory.
MOV CX,CRT_LEN
SUB DI,CX
MOV CRT_START,DI
SHR CX,1
MOV DS,VIDEO_SEGMENT
REP MOVSW
POP DS ;Restore registers.
POP SI
ADD DI,AX ;Adjust for extra line.
MOV CRT_END,DI ;Store as new CRT end.
MOVE_CRT: SUB CRT_END,AX ;Move CRT end up one line.
SUB CRT_START,AX ;Move CRT start up one line.
RET
;---------------------------------;
CK_CRT_END: MOV DI,CRT_END ;Retrieve current CRT end.
CMP DI,THIRTY_K ;End of video memory?
JB CK_END ;If no, done here.
PUSH SI ;Else, save file pointer
PUSH DS ; and data segment.
MOV SI,CRT_START ;Move page down to start
XOR DI,DI ; of video memory.
MOV CRT_START,DI
MOV CX,CRT_LEN
SHR CX,1
MOV DS,VIDEO_SEGMENT
REP MOVSW
POP DS ;Restore registers.
POP SI
CK_END: RET
;---------------------------------;
CK_BACKWARD: CALL GET_INDEX ;Set file pointer to
SUB SI,AX ; previous line.
CMP SI,OFFSET FILE_BUFFER ;Out of range of buffer?
JAE BACKWARD_END ;If no, done here.
PUSH SI ;Else, preserve registers.
PUSH BX
CALL BACKWARD ;Rearrange buffer and read
POP BX ; in previous 30K of file.
POP SI
ADD SI,THIRTY_K ;Adjust file pointer.
BACKWARD_END: MOV LAST_LINE,SI ;Save last line.
RET
;-------------------------------------------------;
; OUTPUT: AX = length in bytes of previous line. ;
;-------------------------------------------------;
GET_INDEX: PUSH DS ;Preserve data segment.
MOV DS,INDEX_SEGMENT ;Second 64K is used for
MOV AX,DS:[BP] ; index of line length.
POP DS
RET
;-----------------------------------------------------------------------;
; INPUT: BX = Desired scan line times two; CX = Offset of video start. ;
;-----------------------------------------------------------------------;
SET_CRT: MOV DX,CS:STATUS_REG ;Retrieve status register.
CLI ;No interrupts.
HORIZONTAL: IN AL,DX ;Wait for horizontal trace
TEST AL,8 ; so will catch vertical
JZ HORIZONTAL ; retrace at start.
VERTICAL: IN AL,DX ;Wait for vertical retrace.
RCR AL,1
JC VERTICAL
SUB DX,6 ;Point to CRT index register.
MOV AL,8 ;Index to preset row scan.
OUT DX,AL
INC DX
SHR BX,1 ;Convert scan line times two
MOV AL,BL ; to actual scan line (div 2).
OUT DX,AL
DEC DX ;Back to index register.
MOV BX,0D0CH ;Set video offset.
CALL SET_ADDRESS
DEC DX ;Back to index register.
MOV BX,0F0EH ;Hide cursor by setting
MOV CX,CRT_END ; CRT end.
CALL SET_ADDRESS
STI
RET ;Interrupts back on.
SET_ADDRESS: SHR CX,1 ;Address has to be divided by 2.
MOV AL,BL ;Most significant byte.
OUT DX,AL
INC DX
MOV AL,CH ;Write it.
OUT DX,AL
DEC DX ;Next index.
MOV AL,BH
OUT DX,AL
INC DX
MOV AL,CL ;Least significant byte.
OUT DX,AL ;Write it.
RET
;---------------------------------------------------------------------------;
; A line is marked by either a carriage return or reaching the last column. ;
;---------------------------------------------------------------------------;
ADVANCE: XOR DX,DX ;Use DX as counter.
CALL LINES ;Write a line.
PUSH DS
MOV DS,INDEX_SEGMENT
MOV DS:[BP],DX ;Save length of line.
POP DS
INC BP ;Move to new index.
INC BP
JNZ ADVANCE_END ;If 32K lines exceeded,
JMP EXIT ; too much; give up.
ADVANCE_END: RET
;---------------------------------;
LINES: MOV CX,CRT_COLS ;Retrieve columns.
MOV LAST_LINE,SI ;Save current line as new last.
NEXT_LINES: CMP SI,FILE_END ;End of buffer?; If no, continue.
JB GET_LINES
CMP FILE_END,OFFSET FILE_BUFFER + (THIRTY_K * 2)
JB PAD_SPACES ;If end of file, pad with spaces.
PUSH BX ;If end of buffer, save
PUSH CX ; our pointers and
PUSH DX
PUSH DI ; read next 30K.
CALL FORWARD
POP DI ;Restore pointers.
POP DX
POP CX
POP BX
GET_LINES: MOV AH,ATTRIBUTE ;Retrieve attribute.
LODSB ;Get a byte.
INC DX ;Increment counter.
AND AL,STRIP_MASK ;Strip high bit for WordStar?
CMP AL,CR ;Carriage return?
JZ PAD_SPACES ;If yes, pad balance of line.
CMP AL,TAB ;Is it tab character?
JZ DO_TAB ;If yes, tab.
CMP AL,LF ;Is it linefeed?
JZ NEXT_LINES ;If yes, skip.
CMP STORE_FLAG,1 ;Else, write to video memory?
JNZ NEXT_BYTES ;If no, next byte.
STOSW ;Else, store the byte/attribute.
NEXT_BYTES: LOOP NEXT_LINES ;Get next byte.
CMP BYTE PTR [SI],CR ;Adjust if next byte CR after
JNZ END_LINES ; complete line to avoid double
INC SI ; spacing.
INC DX
END_LINES: RET
DO_TAB: PUSH CX ;Save counter.
DEC CX ;Adjust column counter.
AND CX,7 ;Get bottom three bits.
INC CX ;Adjust.
PUSH CX
CALL PAD_SPACES ;Move to next tab position.
POP AX
POP CX
SUB CX,AX ;Adjust counter.
JNZ NEXT_LINES ;Next byte if last column.
RET
PAD_SPACES: MOV AL,SPACE ;Space character.
CK_DISPLAY: CMP STORE_FLAG,1 ;Are we to write it to screen?
JNZ CK_DISP_END ;If no, return.
WRITE_VIEW: REP STOSW ;Else, write CX spaces/attribute.
CK_DISP_END: RET
;-----------------------------------------------------;
; OUTPUT: CY = 0 if not file end; CY = 1 if file end. ;
;-----------------------------------------------------;
CK_FILE_END: CMP SI,FILE_END
JB NOT_FILE_END
CMP FILE_END,OFFSET FILE_BUFFER + (THIRTY_K * 2)
JAE NOT_FILE_END
STC
RET
NOT_FILE_END: CLC
RET
;-------------------------------------------------------------------;
; These two subroutines read either the next or previous 30K bytes. ;
;-------------------------------------------------------------------;
FORWARD: XOR CX,CX ;Zero in high half; Move file
MOV DX,THIRTY_K ; pointer forward 30K.
SUB LAST_LINE,DX ;Adjust last line 30K.
CALL MOVE_POINTER
FIRST_READ: MOV SI,OFFSET FILE_BUFFER + THIRTY_K
MOV DI,OFFSET FILE_BUFFER ;Move second half of buffer
CALL MOVE_BUFFER ; to first half and read 30K.
MOV CX,-1 ;Move file pointer back.
NEG DX
MOVE_POINTER: MOV BX,FILE_HANDLE
MOV AX,4201H ;Move file pointer via DOS.
INT 21H
RET
BACKWARD: MOV CX,-1 ;Move pointer back 30K.
MOV DX,- (THIRTY_K * 2)
CALL MOVE_POINTER
MOV SI,OFFSET FILE_BUFFER ;Move first half of
MOV DI,OFFSET FILE_BUFFER + THIRTY_K ; buffer to second.
MOVE_BUFFER: PUSH ES ;Preserve extra segment.
PUSH CS
POP ES
MOV DX,SI ;Save file pointer.
MOV CX,THIRTY_K / 2 ;Move 15K words (30K bytes).
REP MOVSW
MOV BX,FILE_HANDLE
MOV CX,THIRTY_K ;Read 30K.
MOV AH,3FH
INT 21H
MOV SI,DX ;Restore file pointer.
MOV DX,AX
ADD AX,OFFSET FILE_BUFFER + THIRTY_K
MOV FILE_END,AX ;Store end of buffer offset.
POP ES
RET
;--------------------------------------------------;
; INPUT: SI points to parameter start. ;
; OUTPUT: SI points to parameter end; BX = number. ;
;--------------------------------------------------;
DECIMAL_INPUT: XOR BL,BL ;Start with zero.
NEXT_DECIMAL: LODSB ;Get a character.
SUB AL,"0" ;ASCII to binary.
JC DECIMAL_END ;If not between 0 and 9, skip.
CMP AL,9
JA DECIMAL_END
XCHG AL,BL
MOV CL,10 ;Multiply current by 10 to
MUL CL ; shift left one decimal.
ADD BL,AL ;Add new number and store in BX.
JMP SHORT NEXT_DECIMAL
DECIMAL_END: DEC SI ;Adjust pointer.
RET
;------------------------;
; INPUT: BL = Attribute. ;
;------------------------;
SET_BORDER: XOR BH,BH
MOV CL,4 ;Use background attribute
SHR BL,CL ; for border.
MOV AH,0BH
INT 10H
RET
SET_CURSOR: XOR BH,BH
MOV AH,2 ;Set cursor position.
INT 10H
RET
PRINT_STRING: MOV AH,9
INT 21H
RET
FILE_BUFFER = $
_TEXT ENDS
END START